package com.qying.limit;

/**
 * 漏桶算法 Leaky bucket
 *
 * 漏桶算法面对限流更加柔性,不存在直接的粗暴拒绝
 * 原理：
 *     就是注水漏水的过程, 往漏桶中以任意速率流入水, 以固定的速率流出水
 *     当水超过桶的容量时,会被溢出,也就是被丢弃。因为桶容量是不变的,
 *     保证了整体的速率
 *
 *     流入的水滴,可以看作是访问系统的请求,这个流入速率是不确定的
 *     桶的容量一般表示系统所能处理的请求数
 *     如果桶的容量满了,就达到限流的阈值,就会丢弃水滴(拒绝请求)
 *     流出的水滴,是恒定过滤的,对应服务按照固定的速率处理请求
 *
 *     在正常流量的时候，系统按照固定的速率处理请求，是我们想要的。
 *     但是面对突发流量的时候，漏桶算法还是循规蹈矩地处理请求，
 *     这就不是我们想看到的啦。流量变突发时，我们肯定希望系统
 *     尽量快点处理请求，提升用户体验嘛。
 *
 */
public class LeakyBLimit {

    //每秒处理数(出水率)
    private long rate = 2;

    //当前剩余水量
    private long currentWater = 0;

    //最后刷新时间
    private long refreshTime=System.currentTimeMillis();

    //桶容量
    private long capacity=10;

    public static void main(String[] args) {
        LeakyBLimit limit = new LeakyBLimit();

        for(int i = 0;i< 100;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    boolean b = limit.leakBucketLimitTryAcquire();
                    if (b) {
                        System.out.println("111111111");
                    }else {
                        System.out.println("222222222222");
                    }
                }
            }).start();
        }
    }

    boolean leakBucketLimitTryAcquire(){
        long currentTimeMillis = System.currentTimeMillis();
        long outWater = (currentTimeMillis-refreshTime)/1000 * rate;

        currentWater = Math.max(0, currentWater - outWater);

        refreshTime = currentTimeMillis;

        if (currentWater < capacity) {
            currentWater ++;
            return true;
        }

        return false;

    }


}
